package ru.papergames.battleserver.model.battle.services;

import ru.papergames.Config;
import ru.papergames.battleserver.model.battle.BallColor;
import ru.papergames.battleserver.model.battle.GameBall;
import ru.papergames.battleserver.model.battle.map.BattleMap;
import ru.papergames.battleserver.model.battle.map.Cell;
import ru.papergames.battleserver.model.battle.map.LinesToBeRemovedInfo;

import java.util.*;

/**
 * @author : atroshanin
 */
public class DefaultLinesFinderImpl implements LinesFinder {

    private static DefaultLinesFinderImpl instance = new DefaultLinesFinderImpl();

    public static DefaultLinesFinderImpl getInstance() {
        return instance;
    }

    private DefaultLinesFinderImpl() {
    }

    @Override
    public LinesToBeRemovedInfo findCellsToBeFree(BattleMap map, BallColor color) {
        Set<GameBall> playerBalls = map.getBallsOfColor(color);
        if (playerBalls.size() < Config.LINE_LENGTH) {
            return LinesToBeRemovedInfo.STATIC_EMPTY;
        }
        Set<Cell> cellsToBeFree = new HashSet<Cell>();
        for (GameBall ball : playerBalls) {
            if (cellsToBeFree.contains(ball.getCell())) {
                continue;
            }
            checkLine(map, ball, 0, 1, cellsToBeFree); // vertical
            checkLine(map, ball, 1, 0, cellsToBeFree); // horizontal
            checkLine(map, ball, 1, 1, cellsToBeFree); // diagonal +y
            checkLine(map, ball, 1, -1, cellsToBeFree); // diagonal -y

        }
        return new LinesToBeRemovedInfo(cellsToBeFree, Collections.<Integer>emptyList());
    }

    private List<GameBall> checkLine(BattleMap map, GameBall ball, int dx, int dy, Set<Cell> cellsToBeFree) {
        Cell cell = ball.getCell();
        BallColor ballColor = ball.getColor();
        int cellX = cell.getX();
        int cellY = cell.getY();
        int t = 0;
        List<GameBall> line = new ArrayList<GameBall>();
        line.add(ball);
        boolean v1 = true;
        boolean v2 = true;
        while(true) {
            t++;
            GameBall b1 = v1 ? map.getGameBall(cellX + t * dx, cellY + t * dy) : null;
            GameBall b2 = v2 ? map.getGameBall(cellX - t * dx, cellY - t * dy) : null;
            BallColor c1 = b1 != null ? b1.getColor() : null;
            BallColor c2 = b2 != null ? b2.getColor() : null;
            if (ballColor != c1 && ballColor != c2) {
                break;
            }
            if (ballColor == c1) {
                line.add(b1);
            } else {
                v1 = false;
            }
            if (ballColor == c2) {
                line.add(b2);
            } else {
                v2 = false;
            }
        }
        if (line.size() >= Config.LINE_LENGTH) {
            for (GameBall b : line) {
                cellsToBeFree.add(b.getCell());
            }
            return line;
        }
        return null;
    }
}
